const express = require('express');
const router = express.Router();
const { User, Order, sequelize } = require('../../models');
const { success, failure } = require('../../utils/responses');
const { NotFound, BadRequest } = require('http-errors');
const alipaySdk = require('../../utils/alipay');
const userAuth = require('../../middlewares/user-auth');
const moment = require('moment');
const logger = require('../../utils/logger');

/**
 * 公共方法：查询当前订单
 * @param req
 * @returns {Promise<*>}
 */
async function getOrder(req) {
  const { outTradeNo } = req.body;
  if (!outTradeNo) {
    throw new BadRequest('订单号不能为空。');
  }

  const order = await Order.findOne({
    where: {
      outTradeNo: outTradeNo,
      userId: req.userId,
    },
  });

  // 用户只能查看自己的订单
  if (!order) {
    throw new NotFound(`订单号: ${outTradeNo} 的订单未找到。`);
  }

  if (order.status > 0) {
    throw new BadRequest('订单已经支付或失效，无法付款。');
  }

  return order;
}

/**
 * 支付宝支付
 * POST /alipay/pay/page    电脑页面
 * POST /alipay/pay/wap     手机页面
 */
router.post('/pay/:platform', userAuth, async function (req, res, next) {
  try {
    // 判断是电脑页面，还是手机页面
    const isPC = req.params.platform === 'page';
    const method = isPC ? 'alipay.trade.page.pay' : 'alipay.trade.wap.pay';
    const productCode = isPC ? 'FAST_INSTANT_TRADE_PAY' : 'QUICK_WAP_WAY';

    // 支付订单信息
    const order = await getOrder(req);
    const { outTradeNo, totalAmount, subject } = order;
    const bizContent = {
      product_code: productCode,
      out_trade_no: outTradeNo,
      subject: subject,
      total_amount: totalAmount,
    };

    // 支付页面接口，返回 HTML 代码片段
    const url = alipaySdk.pageExecute(method, 'GET', {
      bizContent,
      returnUrl: `${process.env.PAY_RETURN_URL}/user/alipay/finish`, // 当支付完成后，支付宝跳转地址
      notify_url: `${process.env.PAY_RETURN_URL}/user/alipay/notify`, // 异步通知接口地址
    });
    /**没开通正式支付，需要工商户执照，暂时使用沙箱模拟 */
    const sandboxUrl = url.replace(
      /https:\/\/openapi\.alipay\.com\//g,
      'https://openapi-sandbox.dl.alipaydev.com/'
    );
    success({ res, message: '支付地址生成成功。', data: { url: sandboxUrl } });
  } catch (error) {
    failure({ res, error });
  }
});

/**
 * 支付宝支付成功后，跳转页面
 * GET user/alipay/finish
 */
router.get('/finish', async function (req, res) {
  try {
    const alipayData = req.query;
    const verify = alipaySdk.checkNotifySign(alipayData);
    const { out_trade_no, trade_no, timestamp } = alipayData;
    // 验签成功，更新订单与会员信息
    if (verify) {
      await paidSuccess(out_trade_no, trade_no, timestamp);
      res.send('支付成功');
    } else {
      throw new BadRequest('支付验签失败。');
    }
  } catch (error) {
    failure({ res, error });
  }
});

/**
 * 支付宝异步通知
 * POST /alipay/notify
 */
router.post('/notify', async function (req, res) {
  try {
    const alipayData = req.body;
    const verify = alipaySdk.checkNotifySign(alipayData);
    const { out_trade_no, trade_no, gmt_payment } = alipayData;
    // 如果验签成功，更新订单与会员信息
    if (verify) {
      await paidSuccess(out_trade_no, trade_no, gmt_payment);

      res.send('success');
    } else {
      logger.warn('支付宝验签失败：', alipayData);
      res.send('fail');
    }
  } catch (error) {
    failure({ res, error });
  }
});

router.post('/query', userAuth, async function (req, res) {
  try {
    // 查询订单
    const order = await getOrder(req);

    const result = await alipaySdk.exec('alipay.trade.query', {
      bizContent: {
        out_trade_no: order.outTradeNo,
      },
    });

    // 获取支付结果相关信息
    const { tradeStatus, outTradeNo, tradeNo, sendPayDate } = result;

    // TRADE_SUCCESS 说明支付成功
    if (tradeStatus === 'TRADE_SUCCESS') {
      // 更新订单状态
      await paidSuccess(outTradeNo, tradeNo, sendPayDate);
    }

    success({ res, message: '执行成功，请重新查询订单。' });
  } catch (error) {
    failure({ res, error });
  }
});

/**
 * 支付成功后，更新订单状态和会员信息
 * @param outTradeNo
 * @param tradeNo
 * @param paidAt
 * @returns {Promise<void>}
 */
async function paidSuccess(outTradeNo, tradeNo, paidAt) {
  // 开启事务
  const t = await sequelize.transaction();

  try {
    // 查询当前订单（在事务中）
    const order = await Order.findOne({
      where: { outTradeNo: outTradeNo },
      transaction: t,
      // lock: t.LOCK.SHARE //增加共享锁
      lock: t.LOCK.UPDATE, //增加排他锁
      // lock: true //增加排他锁简写
    });

    // 对于状态已更新的订单，直接返回。防止用户重复请求，重复增加大会员有效期
    if (order.status > 0) {
      return;
    }

    // 更新订单状态（在事务中）
    await order.update(
      {
        tradeNo: tradeNo, // 流水号
        status: 1, // 订单状态：已支付
        paymentMethod: 0, // 支付方式：支付宝
        paidAt: paidAt, // 支付时间
      },
      { transaction: t }
    );

    // 查询订单对应的用户（在事务中）
    const user = await User.findByPk(order.userId, { transaction: t });

    // 将用户组设置为大会员。可防止管理员创建订单，并将用户组修改为大会员
    if (user.role === 0) {
      user.role = 1;
    }

    //    使用moment.js，增加大会员有效期
    user.membershipExpiredAt = moment(user.membershipExpiredAt || new Date())
      .add(order.membershipMonths, 'months')
      .toDate();
    // user.membershipExpiredAt = '2025年10月10日';

    // 保存用户信息（在事务中）
    await user.save({ transaction: t });

    // 提交事务
    await t.commit();
  } catch (error) {
    // 回滚事务
    await t.rollback();

    // 将错误抛出，让上层处理
    throw error;
  }
}

module.exports = router;
